%{
/*
 * mkescan.l: the flex description file for the edbtool2 scanner.
 * Clunix, cezanne@clunix.com, 2005.2
 *
 * Copyright (c) 2005 by Clunix Inc. All Rights Reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define MAX_BUF		8192

#include "mkentity.h"
#include "mkeparser.h"

/* Support for the readline and history libraries.  This allows
 * nicer input on the interactive part of input.
 */

/* Have input call the following function. */
#undef  YY_INPUT
#define YY_INPUT(buf,result,max_size) \
		mke_input((char *)buf, &result, max_size)
#define YY_NO_INPUT

static char	buf[MAX_BUF];
static char	*buf_ptr, *buf_end = buf + MAX_BUF - 1;
static ECMBOOL	buf_overflow;

static void
init_buf(void)
{
	buf_ptr = buf;
	*buf = '\0';
	buf_overflow = ECM_FALSE;
}

static char *
get_buf(void)
{
	buf_ptr = '\0';
	if (buf_overflow)
		return NULL;
	return ecm_strdup(buf);
}

static ECMBOOL
is_empty_buf(void)
{
	return (!buf_overflow && buf == buf_ptr) ? ECM_TRUE: ECM_FALSE;
}

static void
add_chr_to_buf(char c)
{
	if (buf_overflow)
		return;
	if (buf_ptr == buf_end)
		buf_overflow = ECM_TRUE;
	else
		*buf_ptr++ = c;
}

static void
add_str_to_buf(char *str, int len)
{
	if (buf_overflow)
		return;
	if (len == 0)
		len = ecm_strlen(str);
	if ((int)(buf_end - buf_ptr) < len)
		buf_overflow = ECM_TRUE;
	else {
		ecm_strcpy(buf_ptr, str);
		buf_ptr += len;
	}
}

%}

%option yylineno
%option noyyalloc noyyrealloc noyyfree
%option never-interactive

%x sc_str
%x edexpr
%x comment
%x comment2

%%

\/\*		BEGIN(comment);
\/\*\*		BEGIN(comment2);
<comment>\*\/	BEGIN(INITIAL);
<comment2>\*\*\/	BEGIN(INITIAL);
<comment,comment2>.
<comment,comment2>\n

\(		mkelloc.first_line = mkelineno; return LeftRound;
\)		mkelloc.first_line = mkelineno; return RightRound;
,		mkelloc.first_line = mkelineno; return Comma;

=		mkelloc.first_line = mkelineno; return Equal;

\{		mkelloc.first_line = mkelineno; return LeftBrace;
\}		mkelloc.first_line = mkelineno; return RightBrace;

\"		init_buf(); BEGIN(sc_str);
;		mkelloc.first_line = mkelineno; return Semicolon;
\:		mkelloc.first_line = mkelineno; return Colon;
\*		mkelloc.first_line = mkelineno; return Esterik;
\|		mkelloc.first_line = mkelineno; return Pipe;
\!		mkelloc.first_line = mkelineno; return Exclamation;
@		mkelloc.first_line = mkelineno; return At;
&		mkelloc.first_line = mkelineno; return Ampersand;
\$		mkelloc.first_line = mkelineno; return Dollar;
\<		mkelloc.first_line = mkelineno; return LeftAngle;
\>		mkelloc.first_line = mkelineno; return RightAngle;

\[		{
			BEGIN(edexpr);
			init_buf();
			mkelloc.first_line = mkelineno; return LeftSquare;
		}
\]		mkelloc.first_line = mkelineno; return RightSquare;

@update		mkelloc.first_line = mkelineno; return AttrUpdate;
@fetch		mkelloc.first_line = mkelineno; return AttrFetch;
@owner		mkelloc.first_line = mkelineno; return Owner;
@system		mkelloc.first_line = mkelineno; return System;
@user		mkelloc.first_line = mkelineno; return AtUser;
@group		mkelloc.first_line = mkelineno; return AtGroup;
@perm		mkelloc.first_line = mkelineno; return Perm;

@member		mkelloc.first_line = mkelineno; return Member;

^\%function	mkelloc.first_line = mkelineno; return FuncSection;
^\%entity	mkelloc.first_line = mkelineno; return EntitySection;
^\%ientry	mkelloc.first_line = mkelineno; return IEntrySection;
^\%ui		mkelloc.first_line = mkelineno; return UISection;
^\%menu		mkelloc.first_line = mkelineno; return MenuSection;
^\%user		mkelloc.first_line = mkelineno; return UserSection;
^\%group	mkelloc.first_line = mkelineno; return GroupSection;
^\%area		mkelloc.first_line = mkelineno; return AreaSection;

[1-9][:number:]*	{
			mkelval.s_value = ecm_strdup(yytext);
			mkelloc.first_line = mkelineno;
			return NaturalNumber;
		}
[_[:alpha:]]+[_[:alnum:]]*	{
			mkelval.s_value = ecm_strdup(yytext);
			mkelloc.first_line = mkelineno;
			return Identifier;
		}
[_[:alnum:]]+	{
			mkelval.s_value = ecm_strdup(yytext);
			mkelloc.first_line = mkelineno;
			return AlphaNum;
		}
\/[_[:alnum:]]+(\/[_[:alnum:]]*)*	{
			mkelval.s_value = ecm_strdup(yytext);
			mkelloc.first_line = mkelineno;
			return LNPath;
		}
[^\n\r[:blank:]\*\[\];\{\}\"<>=\|,\(\)@&\!\$\:]+	{
			mkelval.s_value = ecm_strdup(yytext);
			mkelloc.first_line = mkelineno;
			return String;
		}

[\n\r[:blank:]]	
<<EOF>>		return ENDOFFILE;

<sc_str>\"		{
			BEGIN(INITIAL);
			mkelval.s_value = get_buf();
			if (mkelval.s_value == NULL) {
				mkelloc.first_line = mkelineno;
				return TooLongString;
			}
			mkelloc.first_line = mkelineno;
			return String;
		}

<sc_str>\\[0-7]{1,3} {
			/* octal escape sequence */
			int	result;
			ecm_sscanf(yytext + 1, "%o", &result);
			if (result > 0xff)
				;
			add_chr_to_buf((char)result);
		}

<sc_str>\\[0-9]+	{
			/* generate error */
		}

<sc_str>\\n	add_chr_to_buf('\n');
<sc_str>\\t	add_chr_to_buf('\t');
<sc_str>\\r	add_chr_to_buf('\r');
<sc_str>\\b	add_chr_to_buf('\b');
<sc_str>\\f	add_chr_to_buf('\f');
<sc_str>\\\\	add_chr_to_buf('\\');
<sc_str>\\\"	add_chr_to_buf('"');
<sc_str>\\[ ]	add_chr_to_buf(' ');
<sc_str>\\(.|\n|\r\n)	

<sc_str>[^\\\"]+	add_str_to_buf(yytext, yyleng);

<edexpr>\]	{
			BEGIN(INITIAL);
			mkelloc.first_line = mkelineno;
			unput(']');
			if (!is_empty_buf()) {
				mkelval.s_value = get_buf();
				if (mkelval.s_value == NULL)
					return TooLongEDExpr;
				else
					return EDExpr;
			}
		}

<edexpr>[[:blank:]\n]+ {
			if (!is_empty_buf())
				add_str_to_buf(yytext, yyleng);
		}

<edexpr>[^\]\\;]+  	add_str_to_buf(yytext, yyleng);

<edexpr>\\.	{
			add_chr_to_buf(yytext[1]);
		}

<edexpr>;	{
			mkelval.s_value = get_buf();
			mkelloc.first_line = mkelineno;
			if (mkelval.s_value == NULL) {
				init_buf();
				return TooLongEDExpr;
			}
			else {
				init_buf();
				return EDExpr;
			}
		}

%%

void
mkeerror(char *msg)
{
}

int
yywrap(void)
{
	return 1;
}

void *
yyalloc(yy_size_t bytes)
{
	return ecm_malloc(bytes);
}

void *
yyrealloc(void *ptr, yy_size_t bytes)
{
	return ecm_realloc(ptr, bytes);
}

void
yyfree(void *ptr)
{
	ecm_free(ptr);
}
